package com.scs.application.modules.dept.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UtilNum;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrUnit;
import com.scs.application.modules.base.entity.PackTempletItem;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.service.MatrUnitService;
import com.scs.application.modules.base.service.PackTempletItemService;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.dept.entity.Apply;
import com.scs.application.modules.dept.entity.ApplyItem;
import com.scs.application.modules.dept.mapper.ApplyItemMapper;
import com.scs.application.modules.dept.mapper.ApplyMapper;
import com.scs.application.modules.dept.service.ApplyItemService;
import com.scs.application.modules.purchase.enums.PurchaseType;
import com.scs.application.modules.wm.dto.StockGroupWarehouseMatrDTO;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.entity.Transfer;
import com.scs.application.modules.wm.entity.TransferDemand;
import com.scs.application.modules.wm.mapper.TransferDemandMapper;
import com.scs.application.modules.wm.service.StockService;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 科室请领单明细 服务实现类
 * </p>
 */
@Service
public class ApplyItemServiceImpl extends BaseServiceImpl<ApplyItemMapper, ApplyItem> implements ApplyItemService {
    @Autowired
    private ApplyMapper applyMapper;

    @Autowired
    private MatrMapper matrMapper;
    @Autowired
    private TransferDemandMapper transferDemandMapper;

    @Autowired
    StockService stockService;

    @Autowired
    private PackTempletItemService packTempletItemService;

    @Autowired
    private MatrUnitService matrUnitService;

    private static ApplyItemServiceImpl instThis;
    private static String remarkMark =" 第%s次配送 单号:%s 状态:%s ";
    @PostConstruct
    public void init() {
        instThis = this;
        this.transferDemandMapper = transferDemandMapper;
    }


    @Override
    public boolean saveOrUpdate(ApplyItem entity) {

        if (entity.getPackageQty() <= 0) throw new BusinessException("包装数量不能小于等于0，请检查申请明细");

        if (StringUtils.isBlank(entity.getApplyType())) {
            entity.setApplyType("1"); //默认为请领
        }

        // 请领类耗材
        if ("1".equals(entity.getApplyType()) && !ParameterUtils.isAllowOverApply()) {
            Apply apply = applyMapper.selectById(entity.getApplyId());
            if (apply == null) throw new BusinessException("请领单未找到，请刷新浏览器重试");
            List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOS = stockService.getListGroupByMatr(Wrappers.<Stock>query()
                    .eq("matr_id", entity.getMatrId()).eq( "warehouse_id", apply.getWarehouseId()));
            Double skuQtyDb = stockGroupWarehouseMatrDTOS.stream()
                    .mapToDouble(StockGroupWarehouseMatrDTO::getSkuQtyUseApply).sum();
            if (entity.getSkuQty() > skuQtyDb) {
                BusinessException.throwValidFail(
                        "商品申请单品数量已超过库存数量，商品:%s,申请单品数量:%s，可用单品数量:%s",
                        entity.getMatrName(),
                        entity.getSkuQty(),
                        skuQtyDb
                );
            }
        }

        Boolean success = super.saveOrUpdate(entity);
        if (success) {//更新主表金额
            applyMapper.updateApplyAOmount(entity.getApplyId());
        }
        return success;
    }


    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        if (idList == null || idList.size() < 1) return false;
        Collection<ApplyItem> items = this.listByIds(idList);
        if (items.isEmpty()) {
            return false;
        }

        List<Apply> applies = applyMapper.selectBatchIds(items.stream().map(ApplyItem::getApplyId).collect(Collectors.toList()));
        super.removeCascadeByIds(idList);
        if (CollectionUtils.isNotEmpty(applies)) {
            Apply apply = applies.get(0);
            List<String> types = baseMapper.getType(apply.getId());
            if (types.stream().noneMatch(type -> PurchaseType.REAGENT.getKey().equals(type))) {
                // 请领明细不包含试剂时，置空试剂组id
                applyMapper.update(null, Wrappers.<Apply>update().set("reagent_team_id", null).eq("id", apply.getId()));
            }
            //更新主表金额
            applies.forEach(ob -> {
                applyMapper.updateApplyAOmount(ob.getId());
            });
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatch(List<ApplyItem> entityList) {
        entityList.forEach(ob -> {
            this.saveOrUpdate(ob);
        });
    }

    /**
     * @Description：科室请领需求批量操作
     * @Author wyt
     * @Date 2020/11/30
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveBatchForApplyDemand(List<ApplyItem> entityList) {
        Date now = DateUtils.now();
        final int[] addNum = {1};
        //非包装耗材
        entityList.stream().forEach(applyItem -> {
            if (StringUtils.isBlank(applyItem.getApplyId())) { throw new BusinessException("主单据保存失败，请刷新浏览器重试"); }

            List<MatrUnit> matrUnits = new ArrayList<>();
            if ("-1".equalsIgnoreCase(applyItem.getPackTempletId())) { //非包装耗材
//                该科室耗材使用最多的包装
                Apply apply = applyMapper.selectById(applyItem.getApplyId());
                if (apply == null) throw new BusinessException("主单据保存失败，请刷新浏览器重试");
                Matr matr = matrMapper.selectById(applyItem.getMatrId());
                applyItem.setApplyType(matr.getFlagCenterPurchase() ? "1" : "2")
                        .setApplyTypeName(matr.getFlagCenterPurchase() ? "请领" : "需求");

                if (this.count(Wrappers.<ApplyItem>query().eq("apply_id", applyItem.getApplyId()).eq("matr_id", applyItem.getMatrId()).last("limit 1")) > 0) {
                    BusinessException.throwValidFail("请勿重复添加耗材，品名：%s", matr.getName());
                }

                MatrUnit applyMaxUnit = baseMapper.getApplyMaxUnit(apply.getDeptId(), applyItem.getMatrId(),applyItem.getApplyType(),matr.getFlagOmoc() == true ? GlobalConsts.YES_STR : GlobalConsts.NO_STR);

                //找到该耗材可用包装转换率最高的一个
                String unitTypeName ="请领";
                if (applyMaxUnit!=null&&StringUtils.isNotBlank(applyMaxUnit.getId())) {
                    matrUnits = Collections.singletonList(applyMaxUnit);
                } else {
                    if (applyItem.getApplyType().equals("1")) {
                        matrUnits = matrUnitService.list(Wrappers.<MatrUnit>query().eq("matr_id", applyItem.getMatrId()).eq("flag_apply", 1).orderByDesc("rate"));
                    }else if (applyItem.getApplyType().equals("2")) {
                        unitTypeName = "采购";
                        if(matr.getFlagOmoc()){
                            matrUnits = matrUnitService.list(Wrappers.<MatrUnit>query().eq("matr_id", applyItem.getMatrId()).eq("flag_purchase", 1).eq("flag_base", 1).orderByDesc("rate"));
                        } else {
                            matrUnits = matrUnitService.list(Wrappers.<MatrUnit>query().eq("matr_id", applyItem.getMatrId()).eq("flag_purchase", 1).orderByDesc("rate"));
                        }
                    }
                }
                if (matrUnits == null || matrUnits.size() < 1)
                    throw new BusinessException("耗材【%s】没有可用【%s】单位，请联系运营人员", applyItem.getMatrName(),unitTypeName);

                applyItem.setPackageRate(matrUnits.get(0).getRate());

                if (applyItem.getPackageQty() != null) {
                    applyItem.setPackageQty(applyItem.getPackageQty());
                    applyItem.setSkuQty(applyItem.getPackageRate() * applyItem.getPackageQty());
                } else {
                    applyItem.setPackageQty(1d);
                    applyItem.setSkuQty(matrUnits.get(0).getRate());
                }
                applyItem.setAmount(applyItem.getSkuQty() * applyItem.getSkuPrice());
                applyItem.setPackageUnit(matrUnits.get(0).getUnit());

				applyItem.setHrpCode(matr.getHrpCode());

                applyItem.setBaseType(matr.getBaseType());
                applyItem.setResponseStatusText("未响应");

                this.saveOrUpdate(applyItem);
            } else { //包装耗材
                //子网格是按照名称升序排的，此处按照ID顺序进行添加，保证显示顺序与包装选择时一致
                List<String> PackTempletMatrIds = null;

                if (this.count(Wrappers.<ApplyItem>query().eq("apply_id", applyItem.getApplyId()).eq("pack_templet_id", applyItem.getPackTempletId()).last("limit 1")) > 0) {
                    BusinessException.throwValidFail("请勿重复请领同一模板");
                }

                QueryWrapper queryWrapper = Wrappers.<PackTempletItem>query().eq("pack_templet_id", applyItem.getPackTempletId()).orderByDesc("matr_name");
                if (StringUtils.isNotBlank(applyItem.getPackTempletMatrIds())) {
                    PackTempletMatrIds = Arrays.asList(applyItem.getPackTempletMatrIds().split(","));
                    queryWrapper.in("matr_id", PackTempletMatrIds);
                }
                List<PackTempletItem> packTempletItems = packTempletItemService.list(queryWrapper);
                if (packTempletItems != null && packTempletItems.size() > 0) {
                    packTempletItems.forEach(item -> {
                        ApplyItem applyItemPack = new ApplyItem();
                        BeanUtils.copyProperties(item, applyItemPack);

                        Matr matr = matrMapper.selectById(item.getMatrId());
                        applyItemPack.setId(null);
                        applyItemPack.setPackageRate(item.getSkuQty() / item.getPackageQty())
                                .setSkuPrice(item.getAmount() / item.getSkuQty())
                                .setApplyId(applyItem.getApplyId())
                                .setBaseType(matr.getBaseType())
                                .setApplyType(matr.getFlagCenterPurchase() ? "1" : "2")
                                .setApplyTypeName(matr.getFlagCenterPurchase() ? "请领" : "需求");
                        applyItemPack.setResponseStatusText("未响应");
                        this.saveOrUpdate(applyItemPack);

                        //修改时间加一秒，不然同一时间排序无法顺序排序
                        LocalDateTime dateNext = DateUtils.dateToLocalDateTime(DateUtils.addSeconds(now, addNum[0]));
                        applyItemPack.setGmtCreate(dateNext).setGmtModified(dateNext);
                        this.updateById(applyItemPack);
                        addNum[0]++;

                    });
                }
            }
        });
    }

    @Override
    public Page<Map> page(QueryContext context) {
        Page<Map> page = (Page<Map>) super.page(context);
        if (page.getRecords() != null && page.getRecords().size()> 0) {
            Apply apply =applyMapper.selectById(String.valueOf(page.getRecords().get(0).get("applyId")));
            if (apply ==null) throw new BusinessException("请领主单据已被删除");


            List<String> matrIdList = page.getRecords().stream().map(applyItem -> String.valueOf(applyItem.get("matrId"))).distinct().collect(Collectors.toList());
            QueryWrapper queryWrapper = Wrappers.<Stock>query().in("matr_id", matrIdList).eq("warehouse_id",apply.getWarehouseId());
            List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOS= stockService.getListGroupByMatr(queryWrapper);
            List<String> msgArr = new ArrayList<String>();
            Double canUseCountSkuQty = 0d;
            for(Map applyItem : page.getRecords()){
                //实时库存包装列表
                if (stockGroupWarehouseMatrDTOS != null && stockGroupWarehouseMatrDTOS.size() > 0){
                    List<StockGroupWarehouseMatrDTO> findList = stockGroupWarehouseMatrDTOS.stream()
                            .filter(stockGroupWarehouseMatrDTO -> (String.valueOf(applyItem.get("matrId"))).equals(stockGroupWarehouseMatrDTO.getMatrId()))
                            .collect(Collectors.toList());
                    if (findList != null && findList.size() > 0){
                        msgArr.clear();
                        findList.stream().forEach(stockGroupWarehouseMatrDTO -> msgArr.add(UtilNum.trimZero(stockGroupWarehouseMatrDTO.getPackageQtyUse())+stockGroupWarehouseMatrDTO.getPackageUnit()));

                        canUseCountSkuQty = findList.stream().mapToDouble(StockGroupWarehouseMatrDTO::getSkuQtyUse).sum();
                        applyItem.put("canUseCountMsg",StringUtils.join(msgArr,"\n"));
                        applyItem.put("canUseCountSkuQty",canUseCountSkuQty);
                    }else {
                        applyItem.put("canUseCountMsg","无库存");
                        applyItem.put("canUseCountSkuQty",0);
                    }
                }else {
                    applyItem.put("canUseCountMsg","无库存");
                    applyItem.put("canUseCountSkuQty",0);
                }
            }
        }
        return page;
    }


    /**
     * @Description： 更新状态和数量 调拨单流程状态变化后
     * <p>
     *     ApplyItemServiceImpl.updateResponseStatus(responseStatus,responseStatusText,responseSkuQty,applyItemList,transfer)
     * </p>
     * @param   responseStatus          目标状态 【必须】
     * @param   responseStatusText      目标状态描述 【必须】
     * @param   applyItemIdList         明 细列表  【必须】
     */
    public static void updateResponseForTransferFlowChange(String responseStatus, String responseStatusText, Collection<String> applyItemIdList, Transfer transfer) {
        if (applyItemIdList == null || applyItemIdList.size() < 1) {
            BusinessException.throwValidFail("updateApplyItemStatus applyItemIdList 不能为空");
        }
        _updateResponseStatus(responseStatus,responseStatusText, (List<String>) applyItemIdList,transfer);
    }


    /**
     * @Description： 更新状态和数量 调拨单拣货数量变化后
     * <p>
     *     ApplyItemServiceImpl.updateResponseSkuQtyToZero(applyItemIdList)
     * </p>
     * @param   applyItemIdList         明 细列表  【必须】
     */
    public static void updateResponseForTransferPickChange(List<String> applyItemIdList) {
        if (applyItemIdList == null || applyItemIdList.size() < 1) {
            BusinessException.throwValidFail("updateResponseForTransfer applyItemIdList 不能为空");
        }

        //所有相关的调拨需求
        List<TransferDemand> transferDemandsAll = instThis.transferDemandMapper.selectList(Wrappers.<TransferDemand>query().in("ref_apply_item_id", applyItemIdList));

        List<String> itemIdTo0List = new ArrayList<String>();
        //存在的，更新对应的为相关数量
        if (transferDemandsAll != null && transferDemandsAll.size() > 0) {
            Map<String,List<TransferDemand>> mapByItemId = transferDemandsAll.stream().collect(Collectors.groupingBy(TransferDemand::getRefApplyItemId));
            mapByItemId.keySet().forEach(itemId -> {
                ApplyItemServiceImpl._updateResponseSkuQty(itemId, mapByItemId.get(itemId).stream().mapToDouble(TransferDemand::getPickedSkuQty).sum(), true);
            } );

            itemIdTo0List.addAll(applyItemIdList.stream().filter(tmpId -> !mapByItemId.keySet().contains(tmpId)).collect(Collectors.toList()));
        }else {
            itemIdTo0List.addAll(applyItemIdList);
        }

        //一条都没有的还原状态
        if (itemIdTo0List.size() > 0) {
            instThis.update(
                    Wrappers.<ApplyItem>update()
                            .in("id", applyItemIdList)
                            .setSql(" response_sku_qty = 0,response_status='no',response_status_text='未响应' ")
            );
        }
    }

    /**
     * @Description： 更新状态和数量 调拨单删除后
     * <p>
     *     ApplyItemServiceImpl.updateResponseSkuQtyToZero(applyItemIdList)
     * </p>
     * @param   transferDemandList      被删除相关联的调拨需求  【必须】
     * @param   transfer                被删除的调拨单
     */
    public static void updateResponseForTransferDelete(List<TransferDemand> transferDemandList,Transfer transfer) {
        if (transferDemandList == null || transferDemandList.size() < 1) {
            BusinessException.throwValidFail("updateResponseForTransfer applyItemIdList 不能为空");
        }

        List<String> refApplyItemIdList = transferDemandList.stream().filter(tmp -> StringUtils.isNotBlank(tmp.getRefApplyItemId())).map(TransferDemand::getRefApplyItemId).collect(Collectors.toList());
        if (refApplyItemIdList == null || refApplyItemIdList.size() < 1) {
            return;
        }

        List<ApplyItem> applyItemList = instThis.list(Wrappers.<ApplyItem>query().in("id", refApplyItemIdList));
        if (applyItemList == null || applyItemList.size() != refApplyItemIdList.size() ) {
            BusinessException.throwValidFail("更新请领明细状态失败，数量不匹配");
        }

        Map<String, TransferDemand> transferDemandGroupByApplyItemId = Maps.uniqueIndex(transferDemandList, TransferDemand::getRefApplyItemId);
        if (transferDemandGroupByApplyItemId.keySet().size()  != refApplyItemIdList.size() ) {
            BusinessException.throwValidFail("更新请领明细状态失败，数量不匹配");
        }

        String responseStatusTextTmp="";
        String[] responseStatusTextTmpArr;
        boolean isFind  = false;
        for(ApplyItem applyItem : applyItemList) {

            //响应数量
            applyItem.setResponseSkuQty(applyItem.getResponseSkuQty()-transferDemandGroupByApplyItemId.get(applyItem.getId()).getPickedSkuQty());
            if (applyItem.getResponseSkuQty() <=0) {
                applyItem.setResponseSkuQty(0d);
            }
            applyItem.setResponseSkuQty(UtilNum.getDouble(applyItem.getResponseSkuQty()));

            //响应状态
            responseStatusTextTmp = applyItem.getResponseStatusText();
            responseStatusTextTmpArr = responseStatusTextTmp.split(GlobalConsts.SpecialSymbol.COMMA_CN_WRAP);
            isFind =false;
            for(int i=0;i< responseStatusTextTmpArr.length;i++) {
                if (responseStatusTextTmpArr[i].contains(transfer.getBusKey())) {
                    responseStatusTextTmpArr[i] = String.format(remarkMark,(i+1),transfer.getBusKey(),"已删除") ;
                    isFind = true;
                    break;
                }
            }
            //找到更新状态描述
            if (isFind) {
                applyItem.setResponseStatusText(StringUtils.join(responseStatusTextTmpArr,GlobalConsts.SpecialSymbol.COMMA_CN_WRAP));
            }
            applyItem.setResponseStatus("no");
        }
        instThis.updateBatchById(applyItemList);
    }


    /**
     * @Description： 更新明细响应状态 【一般流程状态变化后调用】
     */
    private static void _updateResponseSkuQty(String  applyItemId,Double responseSkuQty,boolean isReplace) {
        if (responseSkuQty  == null) {
            BusinessException.throwValidFail("updateApplyItemStatus responseSkuQty不能为空");
        }
        if (StringUtils.isBlank(applyItemId)) {
            BusinessException.throwValidFail("updateApplyItemStatus applyItemId不能为空");
        }
        responseSkuQty = UtilNum.getDouble(responseSkuQty);

        //覆盖更新该字段
        if (isReplace) {
            instThis.update(
                    Wrappers.<ApplyItem>update()
                            .eq("id", applyItemId)
                            .set("response_sku_qty", responseSkuQty)
            );
            return;
        }

        //再原有字段值基础上 加或者减
        instThis.update(
                Wrappers.<ApplyItem>update()
                        .eq("id", applyItemId)
                        .setSql(" response_sku_qty = response_sku_qty + ("+ UtilNum.getDouble(responseSkuQty) +")")
        );
    }


    //内部方法
    private static void _updateResponseStatus(String responseStatus,String responseStatusText,List<String>  applyItemIdList,Transfer transfer) {
        if (StringUtils.isBlank(responseStatus)) {
            BusinessException.throwValidFail("updateApplyItemStatus 缺少参数【responseStatus】");
        }
        if (StringUtils.isBlank(responseStatusText)) {
            BusinessException.throwValidFail("updateApplyItemStatus 缺少参数【responseStatusText】");
        }

        List<ApplyItem> applyItemList = instThis.list(Wrappers.<ApplyItem>query().in("id", applyItemIdList));
        if (applyItemList == null || applyItemList.size() != applyItemIdList.size() ) {
            BusinessException.throwValidFail("更新请领明细状态失败，数量不匹配");
        }

        String responseStatusTextTmp="";
        String[] responseStatusTextTmpArr;
        boolean isFind =false;
        for(ApplyItem applyItem : applyItemList) {
            if (applyItem.getIsClose()) {
                BusinessException.throwValidFail("请领明细已作废，不可操作，品名：%s，品规：%s",applyItem.getMatrName(),applyItem.getMatrSpec());
            }
            responseStatusTextTmp = applyItem.getResponseStatusText();
            if (StringUtils.isBlank(responseStatusTextTmp) || "未响应".equals(responseStatusTextTmp)) { //第一次
                responseStatusTextTmp = String.format(remarkMark,1,transfer.getBusKey(),responseStatusText);
            }else {//非第一次
                /**格式 换行
                 *   A001配送中，
                 * A002配送中
                 */
                responseStatusTextTmpArr = responseStatusTextTmp.split(GlobalConsts.SpecialSymbol.COMMA_CN_WRAP);
                isFind =false;
                for(int i=0;i< responseStatusTextTmpArr.length;i++) {
                    if (responseStatusTextTmpArr[i].contains(transfer.getBusKey())) {
                        responseStatusTextTmpArr[i] = String.format(remarkMark,(i+1),transfer.getBusKey(),responseStatusText) ;
                        isFind = true;
                        break;
                    }
                }
                if (isFind) {  //找到匹配的
                    responseStatusTextTmp = StringUtils.join(responseStatusTextTmpArr,GlobalConsts.SpecialSymbol.COMMA_CN_WRAP);
                }else { //未找到
                    responseStatusTextTmp+=GlobalConsts.SpecialSymbol.COMMA_CN_WRAP+String.format(remarkMark,(responseStatusTextTmpArr.length+1),transfer.getBusKey(),responseStatusText);
                }
            }
            applyItem.setResponseStatusText(responseStatusTextTmp);
        }

        instThis.updateBatchById(applyItemList);
    }
}
